AdmittanceTransforms 的六个位姿:导纳定律的坐标桥梁
ros2_controllers(Humble,commit 2105376)的 admittance_controller 里有个容易被一眼扫过的结构体 AdmittanceTransforms(admittance_rule.hpp:43-61):它缓存一个控制周期需要的 6 个位姿,由 get_all_transforms(admittance_rule_impl.hpp:142-167)调 6 次 kinematics_->calculate_link_transform() 填满——第 1 次用参考关节角,后 5 次用当前关节角。为什么恰好是这六个、各自被谁消费?这六个位姿是理解导纳定律坐标系关系的钥匙:力在 sensor frame 测得、重力只在 world frame 是常向量、M/D/K 定义在 control frame、弹簧零点在参考轨迹上,把它们搬进 base frame 全靠这六座桥。文中行号对应锚点 commit 的源码。控制器整体架构见本站《ros2_control 控制器架构与 chainable 机制》。
六个位姿与消费点
导纳定律在 base frame 计算:X_ddot = M⁻¹(F_base − D·X_dot − K·X)(impl:290-292)。定律的输入分别诞生在别的 frame,六个位姿就是搬运工:
| 成员 | 含义 | 关节角 | 消费点 | 用哪部分 |
|---|---|---|---|---|
ref_base_ft_ | 传感器在参考构型下的位姿 | 参考(:147) | :202 存入 state → :261-265 算 X 的零点 | 平移+旋转 |
base_ft_ | 传感器当前位姿 | 当前(:152) | :187 组 R_world_sensor | 仅旋转 |
world_base_ | base 在 world 下的位姿 | 当前(:156) | :187 / :189 / :194-196 三次 | 仅旋转 |
base_cog_ | 工具质心当前位姿 | 当前(:159) | :189 重力力矩杠杆臂 | 仅旋转(配 cog_pos_ 参数) |
base_control_ | control frame 当前位姿 | 当前(:162) | :200 → K/D 共轭旋转(:238/:252)、轴掩码往返(:282-288) | 仅旋转 |
base_tip_ | 末端当前位姿 | 当前(:154) | 无(:155 写入后全包零读取) | — |
参考 vs 当前:两份关节角,两个世界
- 参考世界:第①拍
read_state_reference_interfaces(admittance_controller.cpp:447)读 reference interfaces。这组接口有两个写入者——级联时 JTC 直接写;独立运行时话题经 RealtimeBuffer 由update_reference_from_subscribers(:402-430)写入。基类update()先调话题消费再调update_and_write_commands(chainable_controller_interface.cpp:35→42)。 - 当前世界:第②拍
read_state_from_hardware(:450)读 hardware state interfaces(编码器)。 - 对应工业控制器的设定点 vs 编码器反馈;定律里的 X 是跟随误差的笛卡尔版本。
- 六个位姿里只有
ref_base_ft_住在参考世界——弹簧零点需要「上游要你去哪」。其余五个全是当前构型:力怎么旋转、重力怎么减、参数怎么换系只取决于臂的真实姿态。用参考姿态旋转力读数会在臂滞后于指令时出错,而臂滞后最大的时刻恰是接触加载、力读数最重要的时刻。 - 实测关节角 ≈ 上周期指令(参考 + 累积 Δq),hpp 注释 "at reference + admittance offset joint angles" 说的就是这层物理含义。
力的通路:为什么绕道 world
传感器帧 → world → base,三座桥(base_ft_ / world_base_ / base_cog_):
- 工具重量作为向量只有写在 world 里才是常量
[0,0,−mg](end_effector_weight_[2] = −CoG.force,:126);在 base 里方向随臂姿态变。 - 力矩项
r×w:质心不在测点上时传感器多读一个重力力偶,r = cog_pos_参数经R_world_cog旋到 world(:189、:337)。 - 命名规律:
A_B_= B 在 A 下的位姿;复合时下标相邻相消——R_world_base · R_base_sensor = R_world_sensor(:187 正是这行乘法)。
弹簧零点与两个场景
X = 当前传感器位姿 − 参考传感器位姿(平移相减、旋转取 AngleAxis 对数,:261-265),输出 = 参考 + Δq(:214-223 叠加)。
- 自由空间:F=0,偏移按二阶规律衰减到零,臂跟随上游轨迹——没被碰时必须还在轨道上。
- 接触:稳态 K·X = F,弹簧压缩到与接触力平衡。注入 F_des 后(Humble 版没有这个参数,注入它的完整二次开发过程见本站《AdmittanceController 恒力控制二次开发踩坑记》)稳态变 K·X = F − F_des。
源码里的三处冗余(工业控制器视角的判断)
base_tip_是死计算:全包 grep 只有 hpp:55 声明和 impl:155 写入,零读取,rule 也无 getter 把它递给控制器;git log -S显示随首个 commit9be3bfe2(2022-10-10,PR #370)进入至今无人消费。每周期为它付一次 FK。- 每周期 7 次 FK、1 次重复:
calculate_admittance_rule:260 重算当前构型传感器位姿,输入与base_ft_完全相同(current_joint_pos是 :199 从current_joint_state.positions拷的)。推测是为了让定律函数只依赖AdmittanceState自洽,重复计算是事实。 world_base_对固定基座机器人(fixed_world_frame 与 base 刚连)物理上是常量,仍每周期重算。按工业控制器的标准,这两处都是可缓存项。
要点
- 六个位姿是把力、重力、M/D/K、弹簧零点搬进 base 帧的桥:只有
ref_base_ft_用参考关节角(弹簧零点需要「上游要你去哪」),其余五个全用当前关节角——力怎么旋转、重力怎么减、参数怎么换系只取决于臂的真实姿态。 - 力的通路绕道 world:重量只有在 world 帧才是常向量
[0,0,−mg],先旋到 world 减重力再旋回 base;命名规律A_B_复合时下标相邻相消。 - 三处冗余(工业控制器视角):
base_tip_自首个 commit 起零读取、每周期 7 次 FK 含 1 次重复、world_base_固定基座下物理上是常量——都是可缓存项。
控制器的生命周期、参数系统与实测排坑见本站《AdmittanceController 源码精读与全流程走查》;力控算法层面导纳与 PI 的定位对比,见本站《导纳控制与 PI 控制:力控算法的定位与对比》。